{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "11ab4b85",
   "metadata": {},
   "source": [
    "### File Info\n",
    "- Created on 2021/12/15\n",
    "- note  : Predict and test with VGG19 model\n",
    "- author: Yuze Xuan, Xiaohu Hao, Xuan Wang, Sida Wang"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff6f2329",
   "metadata": {},
   "source": [
    "## 导入包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "15a7f90b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import glob\n",
    "import re\n",
    "import shutil\n",
    "\n",
    "import cv2\n",
    "import numpy as np\n",
    "import sklearn.metrics as metrics\n",
    "from tensorflow.keras.models import load_model\n",
    "\n",
    "from config import *"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12bc2f4a",
   "metadata": {},
   "source": [
    "## 图像加载函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "59dbaf81",
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_image(image_path: str) -> np.ndarray:\n",
    "    \"\"\" 图像加载.\n",
    "    @param image_path: 图像路径.\n",
    "    @return: 图像数据.\n",
    "    \"\"\"\n",
    "    img_data = cv2.imread(image_path)\n",
    "    img_data = cv2.resize(img_data, dsize=IMAGE_SIZE, interpolation=cv2.INTER_AREA)\n",
    "    img_data = img_data.astype(\"float32\")\n",
    "    img_data /= 255.\n",
    "    return np.array(img_data[:, :, :CHANNELS])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c25b8bbb",
   "metadata": {},
   "source": [
    "## 加载模型权重"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2898371e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Metal device set to: Apple M1 Max\n",
      "Model: \"model\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "image_input (InputLayer)     [(None, 256, 256, 3)]     0         \n",
      "_________________________________________________________________\n",
      "block1_conv1 (Conv2D)        (None, 256, 256, 64)      1792      \n",
      "_________________________________________________________________\n",
      "block1_conv2 (Conv2D)        (None, 256, 256, 64)      36928     \n",
      "_________________________________________________________________\n",
      "block1_pool (MaxPooling2D)   (None, 128, 128, 64)      0         \n",
      "_________________________________________________________________\n",
      "block2_conv1 (Conv2D)        (None, 128, 128, 128)     73856     \n",
      "_________________________________________________________________\n",
      "block2_conv2 (Conv2D)        (None, 128, 128, 128)     147584    \n",
      "_________________________________________________________________\n",
      "block2_pool (MaxPooling2D)   (None, 64, 64, 128)       0         \n",
      "_________________________________________________________________\n",
      "block3_conv1 (Conv2D)        (None, 64, 64, 256)       295168    \n",
      "_________________________________________________________________\n",
      "block3_conv2 (Conv2D)        (None, 64, 64, 256)       590080    \n",
      "_________________________________________________________________\n",
      "block3_conv3 (Conv2D)        (None, 64, 64, 256)       590080    \n",
      "_________________________________________________________________\n",
      "block3_conv4 (Conv2D)        (None, 64, 64, 256)       590080    \n",
      "_________________________________________________________________\n",
      "block3_pool (MaxPooling2D)   (None, 32, 32, 256)       0         \n",
      "_________________________________________________________________\n",
      "block4_conv1 (Conv2D)        (None, 32, 32, 512)       1180160   \n",
      "_________________________________________________________________\n",
      "block4_conv2 (Conv2D)        (None, 32, 32, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block4_conv3 (Conv2D)        (None, 32, 32, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block4_conv4 (Conv2D)        (None, 32, 32, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block4_pool (MaxPooling2D)   (None, 16, 16, 512)       0         \n",
      "_________________________________________________________________\n",
      "block5_conv1 (Conv2D)        (None, 16, 16, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block5_conv2 (Conv2D)        (None, 16, 16, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block5_conv3 (Conv2D)        (None, 16, 16, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block5_conv4 (Conv2D)        (None, 16, 16, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block5_pool (MaxPooling2D)   (None, 8, 8, 512)         0         \n",
      "_________________________________________________________________\n",
      "global_average_pooling2d (Gl (None, 512)               0         \n",
      "_________________________________________________________________\n",
      "predictions (Dense)          (None, 4)                 2052      \n",
      "=================================================================\n",
      "Total params: 20,026,436\n",
      "Trainable params: 20,026,436\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "# 选择最优模型权重：多级排序-按val_acc升序，val_loss降序排序\n",
    "weight_list = glob.glob(f'{SAVE_BASE_PATH}/checkpoints/*.hdf5')\n",
    "weight_list = sorted(weight_list, key=lambda x: (-float(re.search(r'(.*)-(.*)-(.*).hdf5', x).group(3)),\n",
    "                                                 float(re.search(r'(.*)-(.*)-(.*).hdf5', x).group(2))))\n",
    "model = load_model(weight_list[0])\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42b724d2",
   "metadata": {},
   "source": [
    "## 加载测试数据集信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ff73426d",
   "metadata": {},
   "outputs": [],
   "source": [
    "LABELS = ['auditorium', 'football', 'gym', 'swimming_pool']\n",
    "PREDICT_RESULT_BASE_PATH = os.path.join(SAVE_BASE_PATH, 'predict')\n",
    "if SAVE_PRED_RESULT_BY_CAT:\n",
    "    for label in LABELS:  # 为预测结果分类别建立存储路径\n",
    "        if not os.path.exists(os.path.join(PREDICT_RESULT_BASE_PATH, label)):\n",
    "            os.makedirs(os.path.join(PREDICT_RESULT_BASE_PATH, label))\n",
    "true_labels, pred_labels = [], []\n",
    "with open(os.path.join(DATASET_BASE_PATH, TEST_INFO_NAME), 'r+') as f:\n",
    "    lines = f.readlines()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d39efe77",
   "metadata": {},
   "source": [
    "## 图像加载及预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ef3e79ff",
   "metadata": {},
   "outputs": [],
   "source": [
    "for line in lines:\n",
    "    if len(line) < 10:  # 排除空行\n",
    "        continue\n",
    "    else:\n",
    "        file_name, true_label = line.strip().split(',')\n",
    "        img_path = os.path.join(os.path.join(DATASET_BASE_PATH, 'test'), file_name)\n",
    "        img = load_image(img_path)\n",
    "        true_labels.append(true_label)\n",
    "        pred_label = LABELS[np.argmax(model.predict(np.array([img])))]\n",
    "        pred_labels.append(pred_label)\n",
    "        if SAVE_PRED_RESULT_BY_CAT:\n",
    "            # 将图像按预测结果保存到对应文件夹中\n",
    "            shutil.copy(img_path, os.path.join(PREDICT_RESULT_BASE_PATH, pred_label))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14ae6505",
   "metadata": {},
   "source": [
    "## 预测精度计算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "99370992",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test acc:0.8869, Test recall:0.8821, Test F1_score:0.8825\n"
     ]
    }
   ],
   "source": [
    "acc = round(metrics.precision_score(true_labels, pred_labels, average='macro'), 4)\n",
    "recall = round(metrics.recall_score(true_labels, pred_labels, average='macro'), 4)\n",
    "f1_score = round(metrics.f1_score(true_labels, pred_labels, average='macro'), 4)\n",
    "\n",
    "print(\"Test acc:{}, Test recall:{}, Test F1_score:{}\".format(acc, recall, f1_score))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
